/*
   Copyright (c) [2023] [魔凤啸天]
   [MFUI] is licensed under Mulan PSL v2.
   You can use this software according to the terms and conditions of the Mulan PSL v2. 
   You may obtain a copy of Mulan PSL v2 at:
            http://license.coscl.org.cn/MulanPSL2 
   THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.  
   See the Mulan PSL v2 for more details.  
*/
#include "core.hpp"
#include<SDL2/SDL_ttf.h>
#include<SDL2/SDL_image.h>
#include<algorithm>
namespace MFUI{
	SDL_Cursor *cursor_ibem=nullptr;
	bool openlib(){
		auto ret=SDL_Init(SDL_INIT_EVERYTHING);
		cursor_ibem=SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
		SDL_SetHint(SDL_HINT_IME_SHOW_UI,"1");
		SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY,"linear");
		SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
		if(!(ret|TTF_Init()|IMG_Init(IMG_INIT_JPG|
										 IMG_INIT_PNG)!=(IMG_INIT_JPG|IMG_INIT_PNG)))return true;
		if(SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,"SDL2错误",SDL_GetError(),nullptr))
		SDL_LogError(SDL_LOG_CATEGORY_ERROR,"%s\n",SDL_GetError());
		return false;
	}
	void closelib(){
		Window::closeall();
		SDL_FreeCursor(cursor_ibem);
		TTF_Quit();
		IMG_Quit();
		SDL_Quit();
	}
	SDL_Renderer* renderer=nullptr;
	void RefCounted::deref(){if(!--_ref)delete this;}
	RefCounted::~RefCounted(){}
	RefCounted::RefCounted(){_ref=0;}
	unsigned int RefCounted::refcount()const{return _ref;}
	void RefCounted::ref(){_ref++;}
	Node::Node():rect({0,0,0,0}),parent(nullptr),redraw(true),notified(true),focus(false){}
	Node::~Node(){for(auto v:children)v->deref();}
	Node* Node::getparent()const{return parent;}
	void Node::onremove(Window* w){
		if(focus)focus=false,_losefocus(w);
		for(auto v:children)v->onremove(w);
	}
	void Node::sortchildren(bool(*cmp)(Node*,Node*)){
		std::sort(children.begin(),children.end(),cmp);
	}
	Node::Node(std::initializer_list<Node*>& children):children(children),
													   rect({0,0,0,0}),parent(nullptr),redraw(true),notified(false),focus(false){
		for(auto n:children){
			n->parent=this;
			n->ref();
		}
	}
	void Node::forceredraw(){redraw=true;}
	void Node::setposition(SDL_FPoint p){
		SDL_FPoint d{p.x-rect.x,p.y-rect.y};
		rect.x=p.x,rect.y=p.y;
		for(auto c:children)c->offsetposition(p);
		redraw=true;
		notifyparent();
	}
	void Node::offsetposition(SDL_FPoint p){
		rect.x+=p.x,rect.y+=p.y;
		for(auto c:children)c->offsetposition(p);
		redraw=true;
		notifyparent();
	}
	void Node::notifyparent(){
		if(parent){
			parent->notified=true;
			parent->notifyparent();
		}
	}
	void Node::removechild(Window* w,size_t index){
		auto iter=children.begin()+index;
		auto v=*iter;
		children.erase(iter);
		v->onremove(w);
		v->parent=nullptr;
		v->deref();
	}
	void Node::removechildren(Window* w,size_t start,size_t end){
		if(start!=end){
			auto i=children.begin(),b=i+start,e=i+end;
			while(b!=e){
				auto v=*(b++);
				v->onremove(w);
				v->parent=nullptr;
				v->deref();
			}
			children.erase(i+start,e);
		}
	}
	void Node::popchildren(Window* w,size_t n){
		auto index=children.size();
		Node::removechildren(w,index-n,index);
	}
	void Node::addchild(Window* w,Node* n){
		children.emplace_back(n);
		n->parent=this;
		n->ref();
		n->onadd(w);
	}
	void Node::addchildren(Window* w,std::initializer_list<Node*> l){
		children.insert(children.end(),l.begin(),l.end());
		for(auto v:l)v->parent=this,v->ref(),v->onadd(w);
	}
	void Node::insertchild(Window* w,Node* n,size_t index){
		children.insert(children.begin()+index,n);
		n->parent=this;
		n->ref();
		n->onadd(w);
	}
	void Node::insertchildren(Window* w,std::initializer_list<Node*> l,size_t index){
		children.insert(children.begin()+index,l.begin(),l.end());
		for(auto v:l)v->parent=this,v->ref(),v->onadd(w);
	}
	size_t Node::childcount(){return children.size();}
	void Node::setsize(SDL_FPoint p){
		rect.w=p.x,rect.h=p.y;
		redraw=true;
		notifyparent();
	}
	void Node::setrect(SDL_FRect& r){
		rect=r;
		notifyparent();
	}
	Node* Node::getchild(size_t index)const{
		if(index<children.size())return children[index];
		return nullptr;
	}
	const SDL_FRect& Node::getrect()const{return rect;}
	void Node::onadd(Window* w){for(auto v:children)v->onadd(w);}
	bool Node::confirmdraw(){return redraw;}
	void Node::draw(Renderer* r,bool updatecache){
		for(auto v:children)v->draw(r,updatecache);
		redraw=false;
	}
	bool Node::focused(){return focus;}
	void Node::_onfocus(Window* w){}
	void Node::_losefocus(Window* w){}
	void Node::setparent(Node* p){parent=p;}
	void Node::swapchild(size_t a,size_t b){
		std::swap(children[a],children[b]);
	}
	static const char* _node_exception="node index out of range";
	void Renderer::drawpoint(int x,int y){SDL_RenderDrawPoint(renderer,x,y);}
	void Renderer::drawpointF(float x,float y){SDL_RenderDrawPointF(renderer,x,y);}
	void Renderer::drawline(int x1,int y1,int x2,int y2){SDL_RenderDrawLine(renderer,x1,y1,x2,y2);}
	void Renderer::drawlineF(float x1,float y1,float x2,float y2){SDL_RenderDrawLineF(renderer,x1,y1,x2,y2);}
	void Renderer::drawrect(const SDL_Rect* r){SDL_RenderDrawRect(renderer,r);}
	void Renderer::drawrectF(const SDL_FRect* r){SDL_RenderDrawRectF(renderer,r);}
	void Renderer::fillrect(const SDL_Rect* r){SDL_RenderFillRect(renderer,r);}
	void Renderer::fillrectF(const SDL_FRect* r){SDL_RenderFillRectF(renderer,r);}
	void Renderer::copy(SDL_Texture* t,const SDL_Rect* srcrect,const SDL_Rect* dstrect){
		SDL_RenderCopy(renderer,t,srcrect,dstrect);
	}
	void Renderer::copyF(SDL_Texture* t,const SDL_Rect* srcrect,const SDL_FRect* dstrect){
		SDL_RenderCopyF(renderer,t,srcrect,dstrect);
	}
	void Renderer::copyEx(SDL_Texture* src,const SDL_Rect* srcrect,const SDL_Rect* dstrect,double angle,const SDL_Point* center,SDL_RendererFlip flip){
		SDL_RenderCopyEx(renderer,src,srcrect,dstrect,angle,center,flip);
	}
	void Renderer::copyExF(SDL_Texture* src,const SDL_Rect* srcrect,const SDL_FRect* dstrect,double angle,const SDL_FPoint* center,SDL_RendererFlip flip){
		SDL_RenderCopyExF(renderer,src,srcrect,dstrect,angle,center,flip);
	}
	void Renderer::clear(){SDL_RenderClear(renderer);}
	void Renderer::settarget(SDL_Texture* t){SDL_SetRenderTarget(renderer,t);}
	SDL_Texture* Renderer::gettarget(){return SDL_GetRenderTarget(renderer);}
	void Renderer::setdrawcolor(SDL_Color c){SDL_SetRenderDrawColor(renderer,c.r,c.g,c.b,c.a);}
	void Renderer::setdefaulttarget(){SDL_SetRenderTarget(renderer,screen);}

	Renderer::~Renderer(){
		SDL_DestroyTexture(screen);
		SDL_DestroyRenderer(renderer);
	}
	Renderer::Renderer(Window* window):parent(window){
		format=SDL_AllocFormat(SDL_PIXELFORMAT_ARGB8888);
		formatbytes=SDL_BYTESPERPIXEL(SDL_PIXELFORMAT_ARGB8888);
		renderer=SDL_CreateRenderer(window->window,-1,SDL_RENDERER_ACCELERATED|SDL_RENDERER_TARGETTEXTURE);
		SDL_SetRenderDrawBlendMode(renderer,SDL_BLENDMODE_BLEND);
		SDL_GetRendererOutputSize(renderer,&window->w,&window->h);
		screen=createtexture(window->w,window->h,SDL_BLENDMODE_BLEND);
		SDL_SetRenderTarget(renderer,screen);
		SDL_SetRenderDrawColor(renderer,0,0,0,255);
		SDL_RenderClear(renderer);
	}
	std::unordered_map<Uint32,Window*> Window::windows;
	Window::Window(const char* title,int width,int height,int flag,Node* root):
	root(root),window(SDL_CreateWindow(title,SDL_WINDOWPOS_CENTERED,
	SDL_WINDOWPOS_CENTERED,width,height,flag)),id(SDL_GetWindowID(window)),renderer(this){
		root->ref();
		root->setsize({(float)w,(float)h});
		root->onadd(this);
		updatecache=true;
		windows.emplace(id,this);
	}
	Window::~Window(){
		windows.erase(id);
		SDL_DestroyWindow(window);
		root->deref();
		for(auto& v:signals)for(auto& n:v.second)n.first->deref();
		for(auto& v:events)for(auto& n:v.second)n.first->deref();
	}
	SDL_FPoint Window::getfsize()const{
		return {(float)w,(float)h};
	}
	SDL_Point Window::getsize()const{
		return {w,h};
	}
	void Renderer::resize(int& w,int& h){
		SDL_DestroyTexture(screen);
		SDL_GetRendererOutputSize(renderer,&w,&h);
		screen=createtexture(w,h,SDL_BLENDMODE_BLEND,SDL_TEXTUREACCESS_TARGET);
		SDL_SetRenderTarget(renderer,screen);
		SDL_SetRenderDrawColor(renderer,0,0,0,255);
		SDL_RenderClear(renderer);
	}
	void Renderer::present(){
		SDL_SetRenderTarget(renderer,nullptr);
		SDL_RenderCopy(renderer,screen,nullptr,nullptr);
		SDL_RenderPresent(renderer);
		SDL_SetRenderTarget(renderer,screen);
	}
	void Window::handleevent(SDL_Event& event){
		if(event.type==SDL_WINDOWEVENT){
			switch(event.window.event){
				case SDL_WINDOWEVENT_RESIZED:
					updatecache=true;
					root->redraw=true;
					w=event.window.data1;
					h=event.window.data2;
					renderer.resize(w,h);
					for(auto& p:tabcount){
						auto n=p.first;
						renderer.setdrawcolor({0,0,0,255});
						renderer.clear();
						n->redraw=true;
						n->draw(&renderer,true);
					}
					break;
				case SDL_WINDOWEVENT_CLOSE:delete this;return;
			}
			auto f=events.find(event.window.event);
			if(f!=events.end()){
				auto& g=f->second;
				size_t i=0,l=g.size();
				std::pair<Node*,WindowCallback> controls[l];
				for(auto& _:g)controls[i++]=_;
				i=0;
				while(i<l){
					auto& v=controls[i++];
					v.second(this,v.first,&event.window);
				}
				if(g.empty())events.erase(f);
			}
		}
		else{
			auto f=signals.find(event.type);
			if(f!=signals.end()){
				auto& g=f->second;
				size_t i=0,l=g.size();
				std::pair<Node*,EventCallback> controls[l];
				for(auto& v:g)controls[i++]=v;
				i=0;
				while(i<l){
					auto& v=controls[i++];
					v.second(this,v.first,&event);
				}
				if(g.empty())signals.erase(f);
			}
		}
	}
	void Window::main(Uint32 maxfps){
		Uint32 timer=0;
		auto framedelay=1000/maxfps;
		SDL_Event event;
		for(;;){
			while(SDL_PollEvent(&event)){
				auto f=windows.find(event.window.windowID);
				if(f!=windows.end())f->second->handleevent(event);
			}
			if(windows.empty())return;
			for(auto& v:windows){
				auto w=v.second;
				auto& r=w->renderer;
				auto& updatecache=w->updatecache;
				w->update();
				auto root=w->root;
				if(root->confirmdraw()){
					if(updatecache){
						updatecache=false;
						r.setdrawcolor({0,0,0,255});
						r.clear();
						root->draw(&r,true);
					}
					else root->draw(&r,false);
					r.present();
				}
			}
			auto t=SDL_GetTicks();
			auto d=t-timer;
			if(d<framedelay)SDL_Delay(framedelay-d);
			timer=t;
		}
	}
	void Window::connect(SDL_EventType type,Node* node,EventCallback callback){
		if(signals[type].emplace(node,callback).second)node->ref();
	}
	void Window::connectwindow(SDL_WindowEventID type,Node* node,WindowCallback callback){
		if(events[type].emplace(node,callback).second)node->ref();
	}
	void Window::disconnect(SDL_EventType type,Node* node){
		auto f=signals.find(type);
		if(f!=signals.end()){
			auto& m=f->second;
			m.erase(node);
			node->deref();
		}
	}
	void Window::disconnectwindow(SDL_WindowEventID type,Node* node){
		auto f=events.find(type);
		if(f!=events.end()){
			auto& m=f->second;
			m.erase(node);
			node->deref();
		}
	}
	void Window::connectwindowresize(Node* node){
		connectwindow(SDL_WINDOWEVENT_RESIZED,node,onwindowresize);
	}
	void Window::disconnectwindowresize(Node* node){
		disconnectwindow(SDL_WINDOWEVENT_RESIZED,node);
	}
	SDL_Texture* Renderer::texturefromsurface(SDL_Surface* s,SDL_BlendMode bm){
		if(s->format!=format){
			auto ret=SDL_CreateTextureFromSurface(renderer,s);
			auto temp=createtexture(s->w,s->h,bm);
			auto target=SDL_GetRenderTarget(renderer);
			SDL_SetRenderTarget(renderer,temp);
			SDL_RenderCopy(renderer,ret,NULL,NULL);
			SDL_SetRenderTarget(renderer,target);
			SDL_DestroyTexture(ret);
			return temp;
		}
		auto ret=SDL_CreateTextureFromSurface(renderer,s);
		SDL_SetTextureBlendMode(ret,bm);
		return ret;
	}
	SDL_Texture* Window::texturefromsurface(SDL_Surface* s,SDL_BlendMode bm){
		return renderer.texturefromsurface(s,bm);
	}
	SDL_Texture* Renderer::createtexture(int w,int h,SDL_BlendMode bm,SDL_TextureAccess acc){
		auto t=SDL_CreateTexture(renderer,format->format,acc,w,h);
		SDL_SetTextureBlendMode(t,bm);
		return t;
	}
	SDL_Texture* Window::createtexture(int w,int h,SDL_BlendMode bm,SDL_TextureAccess acc){
		return renderer.createtexture(w,h,bm,acc);
	}
	SDL_Texture* Renderer::texturefrommem(void* data,size_t size,SDL_BlendMode bm){
		auto s=IMG_LoadTexture_RW(renderer,SDL_RWFromMem(data,size),1);
		if(s){
			int w,h;
			SDL_QueryTexture(s,nullptr,nullptr,&w,&h);
			auto ret=createtexture(w,h,bm,SDL_TEXTUREACCESS_TARGET);
			auto target=SDL_GetRenderTarget(renderer);
			SDL_SetRenderTarget(renderer,ret);
			SDL_RenderCopy(renderer,s,nullptr,nullptr);
			SDL_SetRenderTarget(renderer,target);
			SDL_DestroyTexture(s);
			SDL_SetTextureBlendMode(ret,bm);
			return ret;
		}
		return nullptr;
	}
	SDL_Texture* Window::texturefrommem(void* data,size_t size,SDL_BlendMode bm){
		return renderer.texturefrommem(data,size,bm);
	}
	Uint32 Renderer::getformat()const{return format->format;}
	SDL_Texture* Renderer::texturefromfile(const char* path,SDL_BlendMode bm){
		auto s=IMG_LoadTexture(renderer,path);
		if(s){
			int w,h;
			SDL_QueryTexture(s,nullptr,nullptr,&w,&h);
			auto ret=createtexture(w,h,bm,SDL_TEXTUREACCESS_TARGET);
			auto target=SDL_GetRenderTarget(renderer);
			SDL_SetRenderTarget(renderer,ret);
			SDL_RenderCopy(renderer,s,nullptr,nullptr);
			SDL_SetRenderTarget(renderer,target);
			SDL_DestroyTexture(s);
			SDL_SetTextureBlendMode(ret,bm);
			return ret;
		}
		return nullptr;
	}
	SDL_Texture* Window::texturefromfile(const char* path,SDL_BlendMode bm){
		return renderer.texturefromfile(path,bm);
	}
	void getpointto(SDL_FPoint& start,SDL_FPoint& end,float* x,float* y,float* w,double* angle){
		auto dx=end.x-start.x,dy=end.y-start.y;
		*w=sqrt(dx*dx+dy*dy);
		*x=0.5F*(end.x+start.x-*w);
		*y=0.5F*(end.y+start.y);
		if(dx<0.F)*angle=180.F+(180.F/3.1415926F)*atan(dy/dx);
		else *angle=(180.F/3.1415926F)*atan(dy/dx);
	}
	void getcenterrect(SDL_FRect* box,SDL_FRect* target,SDL_FRect* out){
		*out={box->x+((box->w-target->w)*0.5F),box->y+((box->h-target->h)*0.5F),
			  target->w,target->h};
	}
	void getcenterx(SDL_FRect* box,SDL_FRect* target,float* x){
		*x=box->x+((box->w-target->w)*0.5F);
	}
	void getcentery(SDL_FRect* box,SDL_FRect* target,float* y){
		*y=box->y+((box->h-target->h)*0.5F);
	}
	void getalignrect(SDL_FRect* box,SDL_FRect* target,Align align,SDL_FRect* out){
		*out={box->x,box->y,std::min(box->w,target->w),std::min(box->h,target->h)};
		switch(align){
			case align_nw:return;
			case align_n:getcenterx(box,target,&out->x);return;
			case align_ne:out->x+=box->w-out->w;return;
			case align_w:getcentery(box,target,&out->y);return;
			case align_m:getcenterrect(box,target,out);return;
			case align_e:getcentery(box,target,&out->y);out->x+=box->w-out->w;return;
			case align_sw:out->y+=box->h-out->h;return;
			case align_s:out->y+=box->h-out->h;getcenterx(box,target,&out->x);return;
			case align_se:out->x+=box->w-out->w;out->y+=box->h-out->h;return;
		}
	}
	void surfacedrawfpoint(SDL_Surface* s,SDL_FPoint p,SDL_Color c){
		SDL_Rect r{(int)p.x,(int)p.y,1,1};
		SDL_FillRect(s,&r,*(Uint32*)&c);
	}
	void surfacedrawpoint(SDL_Surface* s,SDL_Point p,SDL_Color c){
		SDL_Rect r{p.x,p.y,1,1};
		SDL_FillRect(s,&r,*(Uint32*)&c);
	}
	void surfacedrawfrect(SDL_Surface* s,SDL_FRect& r,SDL_Color color){
		auto c=*(Uint32*)&color;
		auto w=(int)r.w;
		SDL_Rect rect{(int)r.x,(int)r.y,w,1};
		SDL_FillRect(s,&rect,c);
		rect.w=1,rect.h=r.h;
		SDL_FillRect(s,&rect,c);
		rect.x+=w;
		SDL_FillRect(s,&rect,c);
		rect.x=r.x,rect.y+=r.h,rect.w=w,rect.h=1;
		SDL_FillRect(s,&rect,c);
	}
	void surfacefillfrect(SDL_Surface* s,SDL_FRect& r,SDL_Color c){
		SDL_Rect rect{(int)r.x,(int)r.y,(int)r.w,(int)r.h};
		SDL_FillRect(s,&rect,*(Uint32*)&c);
	}
	void surfacedrawrect(SDL_Surface* s,SDL_Rect& r,SDL_Color color){
		auto c=*(Uint32*)&color;
		auto w=r.w;
		SDL_Rect rect{r.x,r.y,w,1};
		SDL_FillRect(s,&rect,c);
		rect.w=1,rect.h=r.h;
		SDL_FillRect(s,&rect,c);
		rect.x+=w;
		SDL_FillRect(s,&rect,c);
		rect.x=r.x,rect.y+=r.h,rect.w=w,rect.h=1;
		SDL_FillRect(s,&rect,c);
	}
	void surfacefillrect(SDL_Surface* s,SDL_Rect& r,SDL_Color c){
		SDL_FillRect(s,&r,*(Uint32*)&c);
	}
	void surfacefblit(SDL_Surface* _s,SDL_FRect& src,SDL_Surface* _d,SDL_FRect& dst){
		SDL_Rect _src={(int)src.x,(int)src.y,(int)src.w,(int)src.h},
				_dst={(int)dst.x,(int)dst.y,(int)dst.w,(int)dst.h};
		SDL_BlitScaled(_s,&_src,_d,&_dst);
	}
	void surfaceblit(SDL_Surface* _src,SDL_Rect& src,SDL_Surface* _dst,SDL_Rect& dst){
		SDL_BlitScaled(_src,&src,_dst,&dst);
	}
	void Window::onwindowresize(Window* win,Node* n,SDL_WindowEvent* w){
		n->setsize(win->getfsize());
	}
	void Window::setfocus(Node* n){
		if(!n->focus)n->focus=true,n->_onfocus(this);
	}
	void Window::unsetfocus(Node* n){
		if(n->focus)n->focus=false,n->_losefocus(this);
	}
	void Window::setroot(Node* n){
		root->onremove(this);
		root->deref();
		root=n;
		n->ref();
		n->onadd(this);
		n->redraw=true;
		updatecache=true;
	}
	void Window::to(Node* n){
		root->onremove(this);
		tabs.emplace_back(root);
		if(!tabcount.emplace(root,0).first->second++)updatecache=true;
		root->ref();
		root=n;
		n->ref();
		n->onadd(this);
		n->redraw=true;
	}
	void Window::back(){
		root->onremove(this);
		root->deref();
		root=tabs.back();
		tabs.pop_back();
		auto f=tabcount.find(root);
		if(!--f->second)tabcount.erase(f);
		root->deref();
		root->onadd(this);
		root->redraw=true;
	}
	void Window::errormessage(const char* text){
		SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,"错误",text,window);
	}
	void Window::warningmessage(const char* text){
		SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING,"警告",text,window);
	}
	void Window::infomessage(const char* text){
		SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION,"提示",text,window);
	}
	void Window::update(){}
	const Window* Renderer::window(){return parent;}
	void* Renderer::createimagebuffer(int w,int h){return calloc(w*h,formatbytes);}
	void* Window::createimagebuffer(int w,int h){return renderer.createimagebuffer(w,h);}
	Uint8 Window::getbufferbytes()const{return renderer.getbufferbytes();}
	Uint8 Renderer::getbufferbytes()const{return formatbytes;}
	void Renderer::gettexturepixel(SDL_Texture* texture,void* buffer){
		int w;
		SDL_QueryTexture(texture,nullptr,nullptr,&w,nullptr);
		SDL_RenderReadPixels(renderer,nullptr,format->format,buffer,w*formatbytes);
	}
	void Renderer::gettexturepixel(SDL_Texture* texture,void* buffer,int w){
		SDL_RenderReadPixels(renderer,nullptr,format->format,buffer,w*formatbytes);
	}
	void Renderer::gettexturepixel(SDL_Texture* texture,void* buffer,const SDL_Rect* src){
		SDL_RenderReadPixels(renderer,src,format->format,buffer,src->w*formatbytes);
	}
	void Window::gettexturepixel(SDL_Texture* texture,void* buffer,const SDL_Rect* src){
		renderer.gettexturepixel(texture,buffer,src);
	}
	void Window::closeall(){
		for(auto& w:windows)delete w.second;
		windows.clear();
	}
	CacheNode::~CacheNode(){SDL_DestroyTexture(cache);}
	CacheNode::CacheNode():cache(nullptr){}
	CacheNode::CacheNode(std::initializer_list<Node*>& children):Node(children),cache(nullptr){}
	SDL_Texture* Renderer::getdefaulttarget(){return screen;}
	void CacheNode::_draw(Renderer* r,bool updatecache){
		auto b=&rect;
		if(updatecache){
			if(cache)SDL_DestroyTexture(cache);
			cache=r->createtexture(b->w,b->h,SDL_BLENDMODE_BLEND,SDL_TEXTUREACCESS_TARGET);
			r->settarget(cache);
			SDL_Rect _{(int)b->x,(int)b->y,(int)b->w,(int)b->h};
			r->copyF(r->getdefaulttarget(),&_,nullptr);
			r->setdefaulttarget();
		}
		r->setdrawcolor({0,0,0,255});
		r->fillrectF(b);
		r->copyF(cache,nullptr,b);
	}
	void CacheNode::_draw(Renderer* r,SDL_Rect& src,SDL_FRect& dst){
		r->setdrawcolor({0,0,0,255});
		r->fillrectF(&dst);
		r->copyF(cache,&src,&dst);
	}
	void CacheNode::_draw(Renderer* r,SDL_FRect& src,SDL_FRect& dst){
		SDL_Rect _{(int)src.x,(int)src.y,(int)src.w,(int)src.h};
		_draw(r,_,dst);
	}
	void CacheNode::makecircle(Renderer* r,SDL_FRect& dst){
		r->setdrawcolor({255,255,255,0});
		SDL_Rect _{0,0,2,1};
		SDL_FRect rect{dst.x,dst.y,2.f,1.f};
		r->fillrectF(&rect);
		r->copyF(cache,&_,&rect);
		rect.x+=dst.w-2.f,_.x=dst.w-2.f;
		r->fillrectF(&rect);
		r->copyF(cache,&_,&rect);
		_.y=dst.h-1.f,rect.y+=dst.h-1.f;
		r->fillrectF(&rect);
		r->copyF(cache,&_,&rect);
		rect.x=dst.x,_.x=0;
		r->fillrectF(&rect);
		r->copyF(cache,&_,&rect);
		
		--_.y,_.w=1,--rect.y,rect.w=1.f;
		r->fillrectF(&rect);
		r->copyF(cache,&_,&rect);
		rect.x=dst.x+dst.w-1.f,_.x=dst.w-1.f;
		r->fillrectF(&rect);
		r->copyF(cache,&_,&rect);
		_.y=1,rect.y=dst.y+1.f;
		r->fillrectF(&rect);
		r->copyF(cache,&_,&rect);
		_.x=0,rect.x=dst.x;
		r->fillrectF(&rect);
		r->copyF(cache,&_,&rect);
	}
}